// ==============================================================
//	This file is part of Glest (www.glest.org)
//
//	Copyright (C) 2001-2008 Martiño Figueroa
//
//	You can redistribute this code and/or modify it under
//	the terms of the GNU General Public License as published
//	by the Free Software Foundation; either version 2 of the
//	License, or (at your option) any later version
// ==============================================================

#include "client_interface.h"

#include "logger.h"
#include "window.h"

#include "platform_util.h"
#include "game_util.h"
#include "conversion.h"
#include "config.h"
#include "lang.h"
#include "config.h"
#include <stdexcept>
#include <cassert>

#include "leak_dumper.h"

using namespace std;
using namespace Shared::Platform;
using namespace Shared::Util;

#ifdef WIN32

#define snprintf _snprintf

#endif

namespace Glest{ namespace Game{

const bool debugClientInterfacePerf = false;

const int ClientInterface::messageWaitTimeout					= 10000;	//10 seconds
const int ClientInterface::waitSleepTime						= 10;
const int ClientInterface::maxNetworkCommandListSendTimeWait 	= 5;

// =====================================================
//	class ClientInterfaceThread
// =====================================================

ClientInterfaceThread::ClientInterfaceThread(ClientInterface *client) : BaseThread() {
	this->clientInterface 	= client;
	this->uniqueID 			= "ClientInterfaceThread";
}

ClientInterfaceThread::~ClientInterfaceThread() {
	this->clientInterface = NULL;
}

void ClientInterfaceThread::setQuitStatus(bool value) {
	if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s] Line: %d value = %d\n",__FILE__,__FUNCTION__,__LINE__,value);

	BaseThread::setQuitStatus(value);

	if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__);
}

bool ClientInterfaceThread::canShutdown(bool deleteSelfIfShutdownDelayed) {
	bool ret = (getExecutingTask() == false);
	if(ret == false && deleteSelfIfShutdownDelayed == true) {
	    setDeleteSelfOnExecutionDone(deleteSelfIfShutdownDelayed);
	    deleteSelfIfRequired();
	    signalQuit();
	}

	return ret;
}

void ClientInterfaceThread::execute() {
    RunningStatusSafeWrapper runningStatus(this);
	try {
		if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
		if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d] ****************** STARTING worker thread this = %p\n",__FILE__,__FUNCTION__,__LINE__,this);

		// Set socket to non blocking
		if(clientInterface != NULL && clientInterface->getSocket(true) != NULL) {
			clientInterface->getSocket(true)->setBlock(false);
		}

		if(SystemFlags::VERBOSE_MODE_ENABLED) printf("ClientInterfaceThread::exec Line: %d\n",__LINE__);

		time_t clientSimulationLagStartTime = 0;
		Chrono chrono;
		for(;this->clientInterface != NULL;) {

			if(getQuitStatus() == true) {
				if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
				break;
			}

			ExecutingTaskSafeWrapper safeExecutingTaskMutex(this);

			if(debugClientInterfacePerf == true) printf("START === Client thread\n");

			//printf("ClientInterfaceThread::exec Line: %d\n",__LINE__);

			uint64 loopCount = 0;
			if(debugClientInterfacePerf == true) {
				chrono.start();
			}
			while(	this->getQuitStatus() == false &&
					clientInterface != NULL) {
				//printf("ClientInterfaceThread::exec Line: %d this->getQuitStatus(): %d\n",__LINE__,this->getQuitStatus());

				// START: Test simulating lag for the client
				int simulateLag = Config::getInstance().getInt("SimulateClientLag","0");
				if(simulateLag > 0) {
					if(clientSimulationLagStartTime == 0) {
						clientSimulationLagStartTime = time(NULL);
					}
					if(difftime((long int)time(NULL),clientSimulationLagStartTime) <= Config::getInstance().getInt("SimulateClientLagDurationSeconds","0")) {
						sleep(simulateLag);
					}
				}
				// END: Test simulating lag for the client

				clientInterface->updateNetworkFrame();

				//printf("ClientInterfaceThread::exec Line: %d this->getQuitStatus(): %d\n",__LINE__,this->getQuitStatus());

				if(debugClientInterfacePerf == true) {
					loopCount++;
					if(chrono.getMillis() >= 1000) {
						printf("Client thread loopCount = %llu\n",(long long unsigned int)loopCount);

						loopCount = 0;
						//sleep(0);
						chrono.start();
					}
				}
			}

			if(debugClientInterfacePerf == true) {
				printf("END === Client thread\n");
			}

			//printf("ClientInterfaceThread::exec Line: %d\n",__LINE__);

			if(getQuitStatus() == true) {
				if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
				break;
			}

			//printf("ClientInterfaceThread::exec Line: %d\n",__LINE__);
		}

		if(SystemFlags::VERBOSE_MODE_ENABLED) printf("ClientInterfaceThread::exec Line: %d\n",__LINE__);
		if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
		if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d] ****************** ENDING worker thread this = %p\n",__FILE__,__FUNCTION__,__LINE__,this);
	}
	catch(const exception &ex) {

		SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",__FILE__,__FUNCTION__,__LINE__,ex.what());
		if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);

		if(clientInterface == NULL || clientInterface->getSocket(true) == NULL || clientInterface->getSocket(true)->isConnected() == true) {
			throw megaglest_runtime_error(ex.what());
		}
	}
	catch(...) {
		char szBuf[8096]="";
		snprintf(szBuf,8096,"In [%s::%s %d] UNKNOWN error\n",__FILE__,__FUNCTION__,__LINE__);
		SystemFlags::OutputDebug(SystemFlags::debugError,szBuf);
		throw megaglest_runtime_error(szBuf);
	}

	if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__);
}

// =====================================================
//	class ClientInterface
// =====================================================

ClientInterface::ClientInterface() : GameNetworkInterface() {
	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] constructor for %p\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,this);

	networkCommandListThreadAccessor 	= new Mutex(CODE_AT_LINE);
	networkCommandListThread 			= NULL;
	cachedPendingCommandsIndex 			= 0;
	cachedLastPendingFrameCount 		= 0;
	timeClientWaitedForLastMessage 		= 0;

	flagAccessor 						= new Mutex(CODE_AT_LINE);

	clientSocket						= NULL;
	sessionKey 							= 0;
	launchGame							= false;
	introDone							= false;

	this->joinGameInProgress 			= false;
	this->joinGameInProgressLaunch 		= false;
	this->readyForInGameJoin 			= false;
	this->resumeInGameJoin 				= false;

	quitThreadAccessor 					= new Mutex(CODE_AT_LINE);
	setQuitThread(false);

	playerIndex							= -1;
	gameSettingsReceivedCount			= 0;
	setGameSettingsReceived(false);
	gameSettingsReceivedCount			= 0;
	connectedTime 						= 0;
	port 								= 0;
	serverFTPPort 						= 0;

	gotIntro 							= false;
	lastNetworkCommandListSendTime 		= 0;
	currentFrameCount 					= 0;
	lastSentFrameCount 					= 0;
	clientSimulationLagStartTime 		= 0;

	networkGameDataSynchCheckOkMap  	= false;
	networkGameDataSynchCheckOkTile 	= false;
	networkGameDataSynchCheckOkTech 	= false;
	this->setNetworkGameDataSynchCheckTechMismatchReport("");
	this->setReceivedDataSynchCheck(false);
}

void ClientInterface::shutdownNetworkCommandListThread(MutexSafeWrapper &safeMutexWrapper) {
	if(networkCommandListThread != NULL) {
		//printf("START === shutdownNetworkCommandListThread\n");
		if(SystemFlags::VERBOSE_MODE_ENABLED) printf("%s Line: %d\n",__FUNCTION__,__LINE__);

		setQuitThread(true);
		networkCommandListThread->signalQuit();
		safeMutexWrapper.ReleaseLock(true);

		if(SystemFlags::VERBOSE_MODE_ENABLED) printf("%s Line: %d\n",__FUNCTION__,__LINE__);

		Chrono chronoElapsed(true);
		for(;chronoElapsed.getMillis() <= 10000;) {
			safeMutexWrapper.Lock();
			if(networkCommandListThread != NULL &&
				networkCommandListThread->canShutdown(false) == false &&
				 networkCommandListThread->getRunningStatus() == true) {

				safeMutexWrapper.ReleaseLock(true);
				if(chronoElapsed.getMillis() % 1000 == 0) {
					sleep(1);
					if(SystemFlags::VERBOSE_MODE_ENABLED) printf("%s Line: %d\n",__FUNCTION__,__LINE__);
				}
			}
			else {
				safeMutexWrapper.ReleaseLock(true);
				break;
			}
			//printf("%s Line: %d\n",__FUNCTION__,__LINE__);
		}

		if(SystemFlags::VERBOSE_MODE_ENABLED) printf("%s Line: %d\n chronoElapsed.getMillis(): %lld",__FUNCTION__,__LINE__,(long long int)chronoElapsed.getMillis());
		//printf("A === shutdownNetworkCommandListThread\n");

		safeMutexWrapper.Lock();
		if(networkCommandListThread != NULL &&
			networkCommandListThread->canShutdown(true)) {

			if(SystemFlags::VERBOSE_MODE_ENABLED) printf("%s Line: %d\n",__FUNCTION__,__LINE__);

			delete networkCommandListThread;
			networkCommandListThread = NULL;
		}
		else {
			networkCommandListThread = NULL;
		}

		if(SystemFlags::VERBOSE_MODE_ENABLED) printf("%s Line: %d\n",__FUNCTION__,__LINE__);
		//printf("END === shutdownNetworkCommandListThread\n");
	}
}

ClientInterface::~ClientInterface() {
	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] destructor for %p\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,this);
	//printf("START === Client destructor\n");

	if(SystemFlags::VERBOSE_MODE_ENABLED) printf("%s Line: %d\n",__FUNCTION__,__LINE__);

	MutexSafeWrapper safeMutex(networkCommandListThreadAccessor,CODE_AT_LINE);

	if(SystemFlags::VERBOSE_MODE_ENABLED) printf("%s Line: %d\n",__FUNCTION__,__LINE__);

	shutdownNetworkCommandListThread(safeMutex);
	//printf("A === Client destructor\n");

	if(SystemFlags::VERBOSE_MODE_ENABLED) printf("%s Line: %d\n",__FUNCTION__,__LINE__);

    if(clientSocket != NULL &&
    	clientSocket->isConnected() == true) {

    	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);

    	if(SystemFlags::VERBOSE_MODE_ENABLED) printf("%s Line: %d\n",__FUNCTION__,__LINE__);

    	Lang &lang= Lang::getInstance();
    	const vector<string> languageList = this->gameSettings.getUniqueNetworkPlayerLanguages();
    	for(unsigned int langIndex = 0; langIndex < languageList.size(); ++langIndex) {

			string sQuitText = "has chosen to leave the game!";
			if(lang.hasString("PlayerLeftGame",languageList[langIndex]) == true) {
				sQuitText = lang.getString("PlayerLeftGame",languageList[langIndex]);
			}

			if(clientSocket != NULL && clientSocket->isConnected() == true) {
				sendTextMessage(sQuitText,-1,false,languageList[langIndex]);
			}
    	}
    }

    if(SystemFlags::VERBOSE_MODE_ENABLED) printf("%s Line: %d\n",__FUNCTION__,__LINE__);

    //printf("B === Client destructor\n");

    if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);

    close(false);

    if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);

    if(SystemFlags::VERBOSE_MODE_ENABLED) printf("%s Line: %d\n",__FUNCTION__,__LINE__);

	if(SystemFlags::VERBOSE_MODE_ENABLED) printf("%s Line: %d\n",__FUNCTION__,__LINE__);

	//printf("C === Client destructor\n");

	networkCommandListThreadAccessor = NULL;
	safeMutex.ReleaseLock(false,true);

	if(SystemFlags::VERBOSE_MODE_ENABLED) printf("%s Line: %d\n",__FUNCTION__,__LINE__);

	delete flagAccessor;
	flagAccessor = NULL;
	//printf("END === Client destructor\n");

	delete quitThreadAccessor;
	quitThreadAccessor = NULL;

	if(SystemFlags::VERBOSE_MODE_ENABLED) printf("%s Line: %d\n",__FUNCTION__,__LINE__);
	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
}

bool ClientInterface::getQuitThread() {
	MutexSafeWrapper safeMutex(quitThreadAccessor,CODE_AT_LINE);
	return this->quitThread;
}
void ClientInterface::setQuitThread(bool value) {
	MutexSafeWrapper safeMutex(quitThreadAccessor,CODE_AT_LINE);
	this->quitThread = value;
}

bool ClientInterface::getQuit() {
	MutexSafeWrapper safeMutex(quitThreadAccessor,CODE_AT_LINE);
	return this->quit;
}
void ClientInterface::setQuit(bool value) {
	MutexSafeWrapper safeMutex(quitThreadAccessor,CODE_AT_LINE);
	this->quit = value;
}

bool ClientInterface::getJoinGameInProgress() {
	MutexSafeWrapper safeMutex(flagAccessor,CODE_AT_LINE);
	return joinGameInProgress;
}
bool ClientInterface::getJoinGameInProgressLaunch() {
	MutexSafeWrapper safeMutex(flagAccessor,CODE_AT_LINE);
	return joinGameInProgressLaunch;
}

bool ClientInterface::getReadyForInGameJoin() {
	MutexSafeWrapper safeMutex(flagAccessor,CODE_AT_LINE);
	return readyForInGameJoin;
}

bool ClientInterface::getResumeInGameJoin() {
	MutexSafeWrapper safeMutex(flagAccessor,CODE_AT_LINE);
	return resumeInGameJoin;
}

void ClientInterface::connect(const Ip &ip, int port) {
	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] START\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__);

	this->ip    = ip;
	this->port  = port;

	MutexSafeWrapper safeMutex(networkCommandListThreadAccessor,CODE_AT_LINE);
	shutdownNetworkCommandListThread(safeMutex);

	delete clientSocket;
	clientSocket = NULL;

	safeMutex.ReleaseLock();

	clientSocket = new ClientSocket();
	clientSocket->setBlock(false);
	clientSocket->connect(ip, port);
	connectedTime = time(NULL);
	//clientSocket->setBlock(true);

	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] END - socket = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,clientSocket->getSocketId());
}

void ClientInterface::reset() {
    if(getSocket() != NULL) {
    	Lang &lang= Lang::getInstance();
    	const vector<string> languageList = this->gameSettings.getUniqueNetworkPlayerLanguages();
    	for(unsigned int langIndex = 0; langIndex < languageList.size(); ++langIndex) {

			string sQuitText = "has chosen to leave the game!";
			if(lang.hasString("PlayerLeftGame",languageList[langIndex]) == true) {
				sQuitText = lang.getString("PlayerLeftGame",languageList[langIndex]);
			}
			sendTextMessage(sQuitText,-1,false,languageList[langIndex]);
    	}
        close();
    }
}

void ClientInterface::update() {
	bool wasConnected = this->isConnected();
	if(gotIntro == true &&
		wasConnected == false) {
		string playerNameStr = getHumanPlayerName();

    	Lang &lang= Lang::getInstance();

		char szBuf1[8096]="";
		string statusTextFormat= lang.getString("PlayerDisconnected");
		snprintf(szBuf1,8096,statusTextFormat.c_str(),playerNameStr.c_str());

		DisplayErrorMessage(szBuf1);
        setQuit(true);
        return;
	}

	try {
		NetworkMessageCommandList networkMessageCommandList(currentFrameCount);
		for(int index = 0; index < GameConstants::maxPlayers; ++index) {
			networkMessageCommandList.setNetworkPlayerFactionCRC(index,this->getNetworkPlayerFactionCRC(index));
		}

		//send as many commands as we can
		while(requestedCommands.empty() == false) {
			if(networkMessageCommandList.addCommand(&requestedCommands.back())) {
				requestedCommands.pop_back();
			}
			else {
				break;
			}
		}

		double lastSendElapsed = difftime((long int)time(NULL),lastNetworkCommandListSendTime);

		// If we are on a frame that should send packets or we have commands
		// to send now, send it now.
		if((currentFrameCount >= this->gameSettings.getNetworkFramePeriod() &&
			currentFrameCount % this->gameSettings.getNetworkFramePeriod() == 0) ||
				networkMessageCommandList.getCommandCount() > 0) {

			if(lastSentFrameCount < currentFrameCount ||
				networkMessageCommandList.getCommandCount() > 0) {

				lastSentFrameCount = currentFrameCount;
				sendMessage(&networkMessageCommandList);

				lastNetworkCommandListSendTime 	= time(NULL);
				lastSendElapsed 				= 0;
			}
		}

		// If we have not sent anything for maxNetworkCommandListSendTimeWait
		// seconds, send one now.
		if(lastNetworkCommandListSendTime > 0 &&
			lastSendElapsed >= ClientInterface::maxNetworkCommandListSendTimeWait) {

			lastSentFrameCount = currentFrameCount;
			sendMessage(&networkMessageCommandList);
			lastNetworkCommandListSendTime = time(NULL);
		}

		// Possible cause of out of synch since we have more commands that need
		// to be sent in this frame
		if(requestedCommands.empty() == false) {
			if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] WARNING / ERROR, requestedCommands.size() = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,requestedCommands.size());

			string sMsg = "may go out of synch: client requestedCommands.size() = " + intToStr(requestedCommands.size());
			sendTextMessage(sMsg,-1, true,"");
			sleep(1);
		}
	}
	catch(const megaglest_runtime_error &ex) {
		SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] Error [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,ex.what());
		SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,ex.what());

		if(this->isConnected() == false) {
			if(gotIntro == false || wasConnected == false) {
				string sErr = string(extractFileFromDirectoryPath(__FILE__).c_str()) + "::" + string(__FUNCTION__) + " network error: " + string(ex.what());
				DisplayErrorMessage(sErr);
			}

			setQuit(true);
		}
		else {
			throw megaglest_runtime_error(ex.what());
		}
	}
}

std::string ClientInterface::getIpAddress(bool mutexLock) {
	string result = "";
	//MutexSafeWrapper safeMutexSlot((mutexLock == true ? mutexSocket : NULL),CODE_AT_LINE);
	if(clientSocket != NULL) {
		result = clientSocket->getIpAddress();
	}
	return result;
}

std::string ClientInterface::getServerIpAddress() {
	return this->ip.getString();
}

void ClientInterface::updateLobby() {
    NetworkMessageType networkMessageType = getNextMessageType();
    switch(networkMessageType)
    {
        case nmtInvalid:
            break;

        case nmtIntro:
        {
            NetworkMessageIntro networkMessageIntro;
            if(receiveMessage(&networkMessageIntro)) {
            	gotIntro 		= true;
            	sessionKey 		= networkMessageIntro.getSessionId();
            	versionString 	= networkMessageIntro.getVersionString();
				playerIndex		= networkMessageIntro.getPlayerIndex();
				serverName		= networkMessageIntro.getName();
				serverUUID 		= networkMessageIntro.getPlayerUUID();
				serverPlatform 	= networkMessageIntro.getPlayerPlatform();
				serverFTPPort 	= networkMessageIntro.getFtpPort();

				if(playerIndex < 0 || playerIndex >= GameConstants::maxPlayers) {
					throw megaglest_runtime_error("playerIndex < 0 || playerIndex >= GameConstants::maxPlayers");
				}

				MutexSafeWrapper safeMutexFlags(flagAccessor,CODE_AT_LINE);
				this->joinGameInProgress 		= (networkMessageIntro.getGameInProgress() != 0);
				this->joinGameInProgressLaunch 	= false;
				safeMutexFlags.ReleaseLock();

				//printf("Client got intro playerIndex = %d\n",playerIndex);

				if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] got NetworkMessageIntro, networkMessageIntro.getGameState() = %d, versionString [%s], sessionKey = %d, playerIndex = %d, serverFTPPort = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,networkMessageIntro.getGameState(),versionString.c_str(),sessionKey,playerIndex,serverFTPPort);

                //check consistency
				bool compatible = checkVersionComptability(networkMessageIntro.getVersionString(), getNetworkVersionGITString());

				if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] got NetworkMessageIntro, networkMessageIntro.getGameState() = %d, versionString [%s], sessionKey = %d, playerIndex = %d, serverFTPPort = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,networkMessageIntro.getGameState(),versionString.c_str(),sessionKey,playerIndex,serverFTPPort);

				if(compatible == false) {
					if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);

                	bool versionMatched 		= false;
                	string platformFreeVersion 	= getNetworkPlatformFreeVersionString();
                	string sErr 				= "";

                	if(strncmp(platformFreeVersion.c_str(),networkMessageIntro.getVersionString().c_str(),strlen(platformFreeVersion.c_str())) != 0) {
						string playerNameStr = getHumanPlayerName();
    					sErr = "Server and client binary mismatch!\nYou have to use the exactly same binaries!\n\nServer: " + networkMessageIntro.getVersionString() +
    							"\nClient: " + getNetworkVersionGITString() + " player [" + playerNameStr + "]";
                        printf("%s\n",sErr.c_str());

                        sendTextMessage("Server and client binary mismatch!!",-1, true,"");
                        sendTextMessage(" Server:" + networkMessageIntro.getVersionString(),-1, true,"");
                        sendTextMessage(" Client: "+ getNetworkVersionGITString(),-1, true,"");
						sendTextMessage(" Client player [" + playerNameStr + "]",-1, true,"");
                	}
                	else {
                		versionMatched 			= true;
						string playerNameStr 	= getHumanPlayerName();
						sErr = "Warning, Server and client are using the same version but different platforms.\n\nServer: " + networkMessageIntro.getVersionString() +
								"\nClient: " + getNetworkVersionGITString() + " player [" + playerNameStr + "]";
						//printf("%s\n",sErr.c_str());
                	}

                	// error message and disconnect only if checked
					if(Config::getInstance().getBool("PlatformConsistencyChecks","true") &&
					   versionMatched == false) {

						DisplayErrorMessage(sErr);
						sleep(1);

						setQuit(true);
                        close();
                    	return;
            		}
                }

				if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);

                if(networkMessageIntro.getGameState() == nmgstOk) {
                	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);

					//send intro message
                	Lang &lang= Lang::getInstance();
					NetworkMessageIntro sendNetworkMessageIntro(
							sessionKey,getNetworkVersionGITString(),
							getHumanPlayerName(),
							-1,
							nmgstOk,
							this->getSocket()->getConnectedIPAddress(),
							serverFTPPort,
							lang.getLanguage(),
							networkMessageIntro.getGameInProgress(),
							Config::getInstance().getString("PlayerId",""),
							getPlatformNameString());
					sendMessage(&sendNetworkMessageIntro);

					//printf("Got intro sending client details to server\n");

					if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);

					if(clientSocket == NULL ||
						clientSocket->isConnected() == false) {

						if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);

	                	string sErr = "Disconnected from server during intro handshake.";
						DisplayErrorMessage(sErr);
						setQuit(true);
	                    close();

	                    if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
	                	return;
					}
					else {
						if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);

						introDone = true;
					}
                }
                else if(networkMessageIntro.getGameState() == nmgstNoSlots) {
                	string sErr = "Cannot join the server because there are no open slots for new players.";
					DisplayErrorMessage(sErr);
					setQuit(true);
                    close();
                    if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
                	return;
                }
                else {
                	string sErr = "Unknown response from server: " + intToStr(networkMessageIntro.getGameState());
					DisplayErrorMessage(sErr);
					setQuit(true);
                    close();
                    if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
                	return;
                }
            }
        }
        break;

		case nmtPing:
		{
			if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] got nmtPing\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__);

			NetworkMessagePing networkMessagePing;
			if(receiveMessage(&networkMessagePing)) {
				if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
				this->setLastPingInfo(networkMessagePing);
			}
		}
		break;

        case nmtSynchNetworkGameData:
        {
            NetworkMessageSynchNetworkGameData networkMessageSynchNetworkGameData;

            if(receiveMessage(&networkMessageSynchNetworkGameData)) {
            	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] got NetworkMessageSynchNetworkGameData, getTechCRCFileCount() = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,networkMessageSynchNetworkGameData.getTechCRCFileCount());

            	this->setLastPingInfoToNow();

            	networkGameDataSynchCheckOkMap      = false;
            	networkGameDataSynchCheckOkTile     = false;
            	networkGameDataSynchCheckOkTech     = false;
                this->setNetworkGameDataSynchCheckTechMismatchReport("");
                this->setReceivedDataSynchCheck(false);

				uint32 tilesetCRC 	= 0;
				uint32 techCRC	 	= 0;
				uint32 mapCRC	 	= 0;
				vector<std::pair<string,uint32> > vctFileList;

				try {
					Config &config = Config::getInstance();
					string scenarioDir = "";
					if(gameSettings.getScenarioDir() != "") {

						scenarioDir = gameSettings.getScenarioDir();
						if(EndsWith(scenarioDir, ".xml") == true) {
							scenarioDir = scenarioDir.erase(scenarioDir.size() - 4, 4);
							scenarioDir = scenarioDir.erase(scenarioDir.size() - gameSettings.getScenario().size(), gameSettings.getScenario().size() + 1);
						}

						if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] gameSettings.getScenarioDir() = [%s] gameSettings.getScenario() = [%s] scenarioDir = [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,gameSettings.getScenarioDir().c_str(),gameSettings.getScenario().c_str(),scenarioDir.c_str());
					}

					// check the checksum's
					tilesetCRC = getFolderTreeContentsCheckSumRecursively(config.getPathListForType(ptTilesets,scenarioDir), string("/") + networkMessageSynchNetworkGameData.getTileset() + string("/*"), ".xml", NULL);

					this->setNetworkGameDataSynchCheckOkTile((tilesetCRC == networkMessageSynchNetworkGameData.getTilesetCRC()));

					if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] tilesetCRC info, local = %d, remote = %d, networkMessageSynchNetworkGameData.getTileset() = [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,tilesetCRC,networkMessageSynchNetworkGameData.getTilesetCRC(),networkMessageSynchNetworkGameData.getTileset().c_str());

					//tech, load before map because of resources
					techCRC = getFolderTreeContentsCheckSumRecursively(config.getPathListForType(ptTechs,scenarioDir), string("/") + networkMessageSynchNetworkGameData.getTech() + string("/*"), ".xml", NULL);

					this->setNetworkGameDataSynchCheckOkTech((techCRC == networkMessageSynchNetworkGameData.getTechCRC()));

					if(this->getNetworkGameDataSynchCheckOkTech() == false) {

						if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);

						string pathSearchString = "/" + networkMessageSynchNetworkGameData.getTech() + "/*";
						vctFileList = getFolderTreeContentsCheckSumListRecursively(config.getPathListForType(ptTechs,scenarioDir),pathSearchString, ".xml", NULL);

						if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);

						string report = networkMessageSynchNetworkGameData.getTechCRCFileMismatchReport(vctFileList);
						this->setNetworkGameDataSynchCheckTechMismatchReport(report);

					}
					if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] techCRC info, local = %d, remote = %d, networkMessageSynchNetworkGameData.getTech() = [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,techCRC,networkMessageSynchNetworkGameData.getTechCRC(),networkMessageSynchNetworkGameData.getTech().c_str());

					//map
					Checksum checksum;
					string file = Config::getMapPath(networkMessageSynchNetworkGameData.getMap(),scenarioDir, false);
					if(file != "") {
						checksum.addFile(file);
						mapCRC = checksum.getSum();
					}
					this->setNetworkGameDataSynchCheckOkMap((mapCRC == networkMessageSynchNetworkGameData.getMapCRC()));
					this->setReceivedDataSynchCheck(true);

					if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] mapCRC info, local = %d, remote = %d, file = [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,mapCRC,networkMessageSynchNetworkGameData.getMapCRC(),file.c_str());
				}
				catch(const runtime_error &ex) {
					SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,ex.what());
					string sErr = ex.what();
					if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] error during processing, sErr = [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,sErr.c_str());

					DisplayErrorMessage(sErr);
				}

				NetworkMessageSynchNetworkGameDataStatus sendNetworkMessageSynchNetworkGameDataStatus(mapCRC,tilesetCRC,techCRC,vctFileList);
				sendMessage(&sendNetworkMessageSynchNetworkGameDataStatus);
            }
        }
        break;

        case nmtSynchNetworkGameDataFileCRCCheck:
        {
            NetworkMessageSynchNetworkGameDataFileCRCCheck networkMessageSynchNetworkGameDataFileCRCCheck;
            if(receiveMessage(&networkMessageSynchNetworkGameDataFileCRCCheck)) {
            	this->setLastPingInfoToNow();

                Checksum checksum;
                string file = networkMessageSynchNetworkGameDataFileCRCCheck.getFileName();
                checksum.addFile(file);
                uint32 fileCRC = checksum.getSum();

                if(fileCRC != networkMessageSynchNetworkGameDataFileCRCCheck.getFileCRC()) {
                	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] got nmtSynchNetworkGameDataFileCRCCheck localCRC = %d, remoteCRC = %d, file [%s]\n",
                        extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,fileCRC,
                        networkMessageSynchNetworkGameDataFileCRCCheck.getFileCRC(),
                        networkMessageSynchNetworkGameDataFileCRCCheck.getFileName().c_str());

                    // Here we initiate a download of missing or mismatched content

                    NetworkMessageSynchNetworkGameDataFileGet sendNetworkMessageSynchNetworkGameDataFileGet(networkMessageSynchNetworkGameDataFileCRCCheck.getFileName());
                    sendMessage(&sendNetworkMessageSynchNetworkGameDataFileGet);

                    FileTransferInfo fileInfo;
                    fileInfo.hostType   = eClient;
                    fileInfo.serverIP   = this->ip.getString();
                    fileInfo.serverPort = this->port;
                    fileInfo.fileName   = networkMessageSynchNetworkGameDataFileCRCCheck.getFileName();

                    FileTransferSocketThread *fileXferThread = new FileTransferSocketThread(fileInfo);
                    fileXferThread->start();
                }

                if(networkMessageSynchNetworkGameDataFileCRCCheck.getFileIndex() < networkMessageSynchNetworkGameDataFileCRCCheck.getTotalFileCount())
                {
                    NetworkMessageSynchNetworkGameDataFileCRCCheck sendNetworkMessageSynchNetworkGameDataFileCRCCheck(
                        networkMessageSynchNetworkGameDataFileCRCCheck.getTotalFileCount(),
                        networkMessageSynchNetworkGameDataFileCRCCheck.getFileIndex() + 1,
                        0,
                        "");
                    sendMessage(&sendNetworkMessageSynchNetworkGameDataFileCRCCheck);
                }
            }
        }
        break;

        case nmtText:
        {
            NetworkMessageText networkMessageText;
            if(receiveMessage(&networkMessageText)) {
            	this->setLastPingInfoToNow();

            	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] got nmtText\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__);

        		ChatMsgInfo msg(networkMessageText.getText().c_str(),networkMessageText.getTeamIndex(),networkMessageText.getPlayerIndex(),networkMessageText.getTargetLanguage());
        		this->addChatInfo(msg);
            }
        }
        break;

        case nmtMarkCell:
        {
        	NetworkMessageMarkCell networkMessageMarkCell;
            if(receiveMessage(&networkMessageMarkCell)) {
            	this->setLastPingInfoToNow();
            	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] got nmtMarkCell\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__);

            	MarkedCell msg(networkMessageMarkCell.getTarget(),
            			       networkMessageMarkCell.getFactionIndex(),
            			       networkMessageMarkCell.getText().c_str(),
            			       networkMessageMarkCell.getPlayerIndex());
        		this->addMarkedCell(msg);
            }
        }
        break;
        case nmtUnMarkCell:
        {
        	NetworkMessageUnMarkCell networkMessageMarkCell;
            if(receiveMessage(&networkMessageMarkCell)) {
            	this->setLastPingInfoToNow();
            	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] got nmtMarkCell\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__);

            	UnMarkedCell msg(networkMessageMarkCell.getTarget(),
            			       networkMessageMarkCell.getFactionIndex());
        		this->addUnMarkedCell(msg);
            }
        }
        break;
        case nmtHighlightCell:
        {
        	NetworkMessageHighlightCell networkMessageHighlightCell;
            if(receiveMessage(&networkMessageHighlightCell)) {
            	this->setLastPingInfoToNow();
            	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] got nmtHighlightCell\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__);

            	MarkedCell msg(networkMessageHighlightCell.getTarget(),
            			networkMessageHighlightCell.getFactionIndex(),
            			       "none",-1);
        		this->setHighlightedCell(msg);
            }
        }
        break;

        case nmtLaunch:
        case nmtBroadCastSetup:
        {
        	//printf("#1 Got new game setup playerIndex = %d!\n",playerIndex);

            NetworkMessageLaunch networkMessageLaunch;
            if(receiveMessage(&networkMessageLaunch)) {
            	this->setLastPingInfoToNow();

            	if(networkMessageLaunch.getMessageType() == nmtLaunch) {
            		if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Lined: %d] got nmtLaunch\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
            	}
            	else if(networkMessageLaunch.getMessageType() == nmtBroadCastSetup) {
            		if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Lined: %d] got nmtBroadCastSetup\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
            	}
            	else {
            		if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Lined: %d] got networkMessageLaunch.getMessageType() = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,networkMessageLaunch.getMessageType());

					char szBuf[1024]="";
					snprintf(szBuf,1023,"In [%s::%s Line: %d] Invalid networkMessageLaunch.getMessageType() = %d",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,networkMessageLaunch.getMessageType());
					throw megaglest_runtime_error(szBuf);
            	}

                networkMessageLaunch.buildGameSettings(&gameSettings);

                //printf("Client got game settings playerIndex = %d lookingfor match...\n",playerIndex);

                if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Lined: %d] got networkMessageLaunch.getMessageType() = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,networkMessageLaunch.getMessageType());
                //replace server player by network
                for(int factionIndex = 0; factionIndex<gameSettings.getFactionCount(); ++factionIndex) {

                	//printf("Faction = %d start location = %d faction name = %s\n",i,gameSettings.getStartLocationIndex(factionIndex),gameSettings.getFactionTypeName(factionIndex).c_str());

                    //replace by network
                    if(gameSettings.getFactionControl(factionIndex) == ctHuman) {
                        gameSettings.setFactionControl(factionIndex, ctNetwork);
                    }

					//printf("factionIndex = %d gameSettings.getStartLocationIndex(factionIndex) = %d playerIndex = %d, gameSettings.getFactionControl(factionIndex) = %d\n",factionIndex,gameSettings.getStartLocationIndex(factionIndex),playerIndex,gameSettings.getFactionControl(i));

					//set the faction index
					if(gameSettings.getStartLocationIndex(factionIndex) == playerIndex) {
						//printf("Setting my factionindex to: %d for playerIndex: %d\n",i,playerIndex);

                        gameSettings.setThisFactionIndex(factionIndex);

                        //printf("Client got game settings playerIndex = %d factionIndex = %d control = %d name = %s\n",playerIndex,factionIndex,gameSettings.getFactionControl(factionIndex),gameSettings.getFactionTypeName(i).c_str());
                        if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] gameSettings.getThisFactionIndex(factionIndex) = %d, playerIndex = %d, factionIndex = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,gameSettings.getThisFactionIndex(),playerIndex,factionIndex);
                    }
                }

                if(networkMessageLaunch.getMessageType() == nmtLaunch) {
                	launchGame = true;
                }
                else if(networkMessageLaunch.getMessageType() == nmtBroadCastSetup) {
                	setGameSettingsReceived(true);
                }
            }
        }
        break;
		case nmtPlayerIndexMessage:
		{
			PlayerIndexMessage playerIndexMessage(-1);
			if(receiveMessage(&playerIndexMessage)) {
				this->setLastPingInfoToNow();
				playerIndex= playerIndexMessage.getPlayerIndex();

				if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] got nmtPlayerIndexMessage, playerIndex = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,playerIndex);
            }

			//printf("Got player index changed msg: %d\n",playerIndex);
		}
		break;

		case nmtReady:
		{
			NetworkMessageReady networkMessageReady;
			if(receiveMessage(&networkMessageReady)) {
				this->setLastPingInfoToNow();
				MutexSafeWrapper safeMutexFlags(flagAccessor,CODE_AT_LINE);
				this->readyForInGameJoin = true;
			}

			//printf("ClientInterface got nmtReady this->readyForInGameJoin: %d\n",this->readyForInGameJoin);
		}
		break;

		case nmtCommandList:
			{

			//make sure we read the message
			//time_t receiveTimeElapsed = time(NULL);
			NetworkMessageCommandList networkMessageCommandList;
			bool gotCmd = receiveMessage(&networkMessageCommandList);
			if(gotCmd == false) {
				throw megaglest_runtime_error("error retrieving nmtCommandList returned false!");
			}
			this->setLastPingInfoToNow();
		}
		break;

		case nmtQuit:
			{
				//time_t receiveTimeElapsed = time(NULL);
				NetworkMessageQuit networkMessageQuit;
				bool gotCmd = receiveMessage(&networkMessageQuit);
				if(gotCmd == false) {
					throw megaglest_runtime_error("error retrieving nmtQuit returned false!");
				}
				this->setLastPingInfoToNow();
				setQuit(true);
				close();
		}
		break;

		case nmtLoadingStatusMessage:
			{
				NetworkMessageLoadingStatus networkMessageLoadingStatus(nmls_NONE);
				if(receiveMessage(&networkMessageLoadingStatus)) {
					this->setLastPingInfoToNow();
					if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
				}
			}
			break;

        default:
            {
            string sErr = string(extractFileFromDirectoryPath(__FILE__).c_str()) + "::" + string(__FUNCTION__) + " Unexpected network message: " + intToStr(networkMessageType);
            //throw megaglest_runtime_error(string(extractFileFromDirectoryPath(__FILE__).c_str()) + "::" + string(__FUNCTION__) + " Unexpected network message: " + intToStr(networkMessageType));
            sendTextMessage("Unexpected network message: " + intToStr(networkMessageType),-1, true,"");
            DisplayErrorMessage(sErr);
            sleep(1);

            setQuit(true);
            close();
            }
    }

	if( clientSocket != NULL && clientSocket->isConnected() == true &&
		gotIntro == false && difftime((long int)time(NULL),connectedTime) > GameConstants::maxClientConnectHandshakeSecs) {
		if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] difftime(time(NULL),connectedTime) = %f\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,difftime((long int)time(NULL),connectedTime));
		close();
	}
}

void ClientInterface::updateNetworkFrame() {
	this->updateFrame(NULL);
}

void ClientInterface::updateFrame(int *checkFrame) {
	//printf("#1 ClientInterface::updateFrame\n");

	//printf("In updateFrame: %d\n",(checkFrame ? *checkFrame : -1));

	if(isConnected() == true && getQuitThread() == false) {
		//printf("#2 ClientInterface::updateFrame\n");

		uint64 loopCount = 0;
		Chrono chronoPerf;
		if(debugClientInterfacePerf == true) {
			chronoPerf.start();
		}

		int waitMicroseconds = (checkFrame == NULL ? 10 : 0);

		bool done= false;
		while(done == false && getQuitThread() == false) {
			//printf("BEFORE Client get networkMessageType\n");


			//wait for the next message
			NetworkMessageType networkMessageType = waitForMessage(waitMicroseconds);

			//printf("AFTER Client got networkMessageType = %d\n",networkMessageType);

			//check we have an expected message
			//NetworkMessageType networkMessageType= getNextMessageType();

			//printf("Got Network networkMessageType: %d\n",networkMessageType);

			switch(networkMessageType)
			{
				case nmtCommandList:
					{

					//make sure we read the message
					//time_t receiveTimeElapsed = time(NULL);
					NetworkMessageCommandList networkMessageCommandList;
					bool gotCmd = receiveMessage(&networkMessageCommandList);
					if(gotCmd == false) {
						SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] error retrieving nmtCommandList returned false!\n",__FILE__,__FUNCTION__,__LINE__);
						if(isConnected() == false) {
							setQuit(true);
							close();
							return;
						}

						throw megaglest_runtime_error("error retrieving nmtCommandList returned false!");
					}

					//printf("Client Thread getFrameCount(): %d getCommandCount(): %d\n",networkMessageCommandList.getFrameCount(),networkMessageCommandList.getCommandCount());

					MutexSafeWrapper safeMutex(networkCommandListThreadAccessor,CODE_AT_LINE);
					cachedLastPendingFrameCount = networkMessageCommandList.getFrameCount();
					//printf("cachedLastPendingFrameCount = %lld\n",(long long int)cachedLastPendingFrameCount);

					//check that we are in the right frame
					if(checkFrame != NULL) {
						if(networkMessageCommandList.getFrameCount() != *checkFrame) {
							string sErr = "Player: " + getHumanPlayerName() +
										  " got a Network synchronization error, frame counts do not match, server frameCount = " +
										  intToStr(networkMessageCommandList.getFrameCount()) + ", local frameCount = " +
										  intToStr(*checkFrame);
							sendTextMessage(sErr,-1, true,"");
							DisplayErrorMessage(sErr);
							sleep(1);

							setQuit(true);
							close();
							return;
						}
						for(int index = 0; index < GameConstants::maxPlayers; ++index) {
							printf("Frame: %d faction: %d local CRC: %u Remote CRC: %u\n",*checkFrame,index,getNetworkPlayerFactionCRC(index),networkMessageCommandList.getNetworkPlayerFactionCRC(index));

							if(networkMessageCommandList.getNetworkPlayerFactionCRC(index) != getNetworkPlayerFactionCRC(index)) {
								string sErr = "Player: " + getHumanPlayerName() +
											  " got a Network CRC error, CRC's do not match, server CRC = " +
											  uIntToStr(networkMessageCommandList.getNetworkPlayerFactionCRC(index)) + ", local CRC = " +
											  uIntToStr(getNetworkPlayerFactionCRC(index));
								sendTextMessage(sErr,-1, true,"");
								DisplayErrorMessage(sErr);
								sleep(1);

								setQuit(true);
								close();
								return;
							}
						}
					}

					cachedPendingCommands[networkMessageCommandList.getFrameCount()].reserve(networkMessageCommandList.getCommandCount());

					// give all commands
					for(int i= 0; i < networkMessageCommandList.getCommandCount(); ++i) {
						//pendingCommands.push_back(*networkMessageCommandList.getCommand(i));

						//if(networkMessageCommandList.getCommand(i)->getNetworkCommandType() == nctPauseResume) {
							//printf("Network cmd type: %d [%d] frame: %d\n",networkMessageCommandList.getCommand(i)->getNetworkCommandType(),nctPauseResume,networkMessageCommandList.getFrameCount());
						//}

						cachedPendingCommands[networkMessageCommandList.getFrameCount()].push_back(*networkMessageCommandList.getCommand(i));

						if(cachedPendingCommandCRCs.find(networkMessageCommandList.getFrameCount()) == cachedPendingCommandCRCs.end()) {
							cachedPendingCommandCRCs[networkMessageCommandList.getFrameCount()].reserve(GameConstants::maxPlayers);
							for(int index = 0; index < GameConstants::maxPlayers; ++index) {
								cachedPendingCommandCRCs[networkMessageCommandList.getFrameCount()].push_back(networkMessageCommandList.getNetworkPlayerFactionCRC(index));
							}
						}
					}
					safeMutex.ReleaseLock();

					done = true;
				}
				break;

				case nmtPing:
				{
					if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] got nmtPing\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__);

					NetworkMessagePing networkMessagePing;
					if(receiveMessage(&networkMessagePing)) {
						if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
						this->setLastPingInfo(networkMessagePing);
					}
				}
				break;

				case nmtQuit:
				{
					NetworkMessageQuit networkMessageQuit;
					bool gotCmd = receiveMessage(&networkMessageQuit);
					if(gotCmd == false) {
						SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] error retrieving nmtQuit returned false!\n",__FILE__,__FUNCTION__,__LINE__);
						if(isConnected() == false) {
							setQuit(true);
							close();
							return;
						}

						throw megaglest_runtime_error("error retrieving nmtQuit returned false!");
					}
					setQuit(true);
					done = true;
				}
				break;

				case nmtText:
				{
					NetworkMessageText networkMessageText;
					bool gotCmd = receiveMessage(&networkMessageText);
					if(gotCmd == false) {

						SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] error retrieving nmtText returned false!\n",__FILE__,__FUNCTION__,__LINE__);
						if(isConnected() == false) {

							setQuit(true);
							close();
							return;
						}

						throw megaglest_runtime_error("error retrieving nmtText returned false!");
					}

					ChatMsgInfo msg(networkMessageText.getText().c_str(),networkMessageText.getTeamIndex(),networkMessageText.getPlayerIndex(),networkMessageText.getTargetLanguage());
					this->addChatInfo(msg);
				}
				break;

		        case nmtMarkCell:
		        {
		        	NetworkMessageMarkCell networkMessageMarkCell;
		            if(receiveMessage(&networkMessageMarkCell)) {
		            	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] got nmtMarkCell\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__);

		            	MarkedCell msg(networkMessageMarkCell.getTarget(),
		            			       networkMessageMarkCell.getFactionIndex(),
		            			       networkMessageMarkCell.getText().c_str(),
		            			       networkMessageMarkCell.getPlayerIndex());
		        		this->addMarkedCell(msg);
		            }
		        }
		        break;

		        case nmtUnMarkCell:
		        {
		        	NetworkMessageUnMarkCell networkMessageMarkCell;
		            if(receiveMessage(&networkMessageMarkCell)) {
		            	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] got nmtMarkCell\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__);

		            	UnMarkedCell msg(networkMessageMarkCell.getTarget(),
		            			       networkMessageMarkCell.getFactionIndex());
		        		this->addUnMarkedCell(msg);
		            }
		        }
		        break;
		        case nmtHighlightCell:
		        {
		        	NetworkMessageHighlightCell networkMessageHighlightCell;
		            if(receiveMessage(&networkMessageHighlightCell)) {
		            	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] got nmtHighlightCell\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__);

		            	MarkedCell msg(networkMessageHighlightCell.getTarget(),
		            			networkMessageHighlightCell.getFactionIndex(),
		            			       "none",-1);
		        		this->setHighlightedCell(msg);
		            }
		        }
		        break;


				case nmtLaunch:
				case nmtBroadCastSetup:
				{
					//printf("#2 Got new game setup playerIndex = %d!\n",playerIndex);

					NetworkMessageLaunch networkMessageLaunch;
					if(receiveMessage(&networkMessageLaunch)) {

						if(networkMessageLaunch.getMessageType() == nmtLaunch) {
							if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Lined: %d] got nmtLaunch\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
						}
						else if(networkMessageLaunch.getMessageType() == nmtBroadCastSetup) {
							if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Lined: %d] got nmtBroadCastSetup\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
						}
						else {
							if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Lined: %d] got networkMessageLaunch.getMessageType() = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,networkMessageLaunch.getMessageType());

							char szBuf[1024]="";
							snprintf(szBuf,1023,"In [%s::%s Line: %d] Invalid networkMessageLaunch.getMessageType() = %d",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,networkMessageLaunch.getMessageType());
							throw megaglest_runtime_error(szBuf);
						}

						networkMessageLaunch.buildGameSettings(&gameSettings);

						if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Lined: %d] got networkMessageLaunch.getMessageType() = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,networkMessageLaunch.getMessageType());
						//replace server player by network
						for(int i= 0; i<gameSettings.getFactionCount(); ++i) {
							//replace by network
							if(gameSettings.getFactionControl(i)==ctHuman) {
								gameSettings.setFactionControl(i, ctNetwork);
							}

							//printf("i = %d gameSettings.getStartLocationIndex(i) = %d playerIndex = %d!\n",i,gameSettings.getStartLocationIndex(i),playerIndex);

							//set the faction index
							if(gameSettings.getStartLocationIndex(i) == playerIndex) {
								//printf("Setting my factionindex to: %d for playerIndex: %d\n",i,playerIndex);

								gameSettings.setThisFactionIndex(i);
								if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] gameSettings.getThisFactionIndex(i) = %d, playerIndex = %d, i = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,gameSettings.getThisFactionIndex(),playerIndex,i);
							}
						}
					}
				}
				break;


				case nmtLoadingStatusMessage:
					break;

				case nmtInvalid:
					break;

				default:
					{
					sendTextMessage("Unexpected message in client interface: " + intToStr(networkMessageType),-1, true,"");
					DisplayErrorMessage(string(extractFileFromDirectoryPath(__FILE__).c_str()) + "::" + string(__FUNCTION__) + " Unexpected message in client interface: " + intToStr(networkMessageType));
					sleep(1);

					setQuit(true);
					close();
					done = true;
					}
					break;
			}

			if(isConnected() == false && getQuit() == true) {
				done = true;
			}

			if(debugClientInterfacePerf == true) {
				loopCount++;
				if(chronoPerf.getMillis() >= 1000) {
					printf("Client updateFrame loopCount = %llu\n",(long long unsigned int)loopCount);

					loopCount = 0;
					//sleep(0);
					chronoPerf.start();
				}
			}
		}

		if(done == true) {
			MutexSafeWrapper safeMutex(networkCommandListThreadAccessor,CODE_AT_LINE);
			cachedPendingCommandsIndex++;
		}
	}
	//printf("#3 ClientInterface::updateFrame\n");
}

uint64 ClientInterface::getCachedLastPendingFrameCount() {
	MutexSafeWrapper safeMutex(networkCommandListThreadAccessor,CODE_AT_LINE);
	uint64 result = cachedLastPendingFrameCount;
	return result;
}

int64 ClientInterface::getTimeClientWaitedForLastMessage() {
	MutexSafeWrapper safeMutex(networkCommandListThreadAccessor,CODE_AT_LINE);
	uint64 result = timeClientWaitedForLastMessage;
	return result;
}

bool ClientInterface::getNetworkCommand(int frameCount, int currentCachedPendingCommandsIndex) {
	bool result 							= false;
	bool waitForData 						= false;
	uint64 copyCachedLastPendingFrameCount 	= 0;
	uint64 waitCount 						= 0;
	uint64 frameCountAsUInt64				= frameCount;
	timeClientWaitedForLastMessage 			= 0;

	//printf("In getNetworkCommand: %d [%d]\n",frameCount,currentCachedPendingCommandsIndex);

	if(getQuit() == false && getQuitThread() == false) {

		Chrono chrono;
		MutexSafeWrapper safeMutex(NULL,CODE_AT_LINE);

		for(;getQuit() == false && getQuitThread() == false;) {

			if(safeMutex.isValidMutex() == false) {
				safeMutex.setMutex(networkCommandListThreadAccessor,CODE_AT_LINE);
			}
			else {
				safeMutex.Lock();
			}
			copyCachedLastPendingFrameCount = cachedLastPendingFrameCount;

			if(cachedPendingCommands.find(frameCount) != cachedPendingCommands.end()) {

				Commands &frameCmdList = cachedPendingCommands[frameCount];

				//printf("In getNetworkCommand frameCmdList.size(): %d\n",(int)frameCmdList.size());

				if(frameCmdList.empty() == false) {
					for(int index = 0; index < (int)frameCmdList.size(); ++index) {
						pendingCommands.push_back(frameCmdList[index]);
					}
					cachedPendingCommands[frameCount].clear();

					if(frameCount >= 0) {
						for(int index = 0; index < GameConstants::maxPlayers; ++index) {
							//printf("X**X Frame: %d faction: %d local CRC: %u Remote CRC: %u\n",frameCount,index,getNetworkPlayerFactionCRC(index),cachedPendingCommandCRCs[frameCount][index]);

							if(cachedPendingCommandCRCs[frameCount][index] != getNetworkPlayerFactionCRC(index)) {

								printf("X**X Frame: %d faction: %d local CRC: %u Remote CRC: %u\n",frameCount,index,getNetworkPlayerFactionCRC(index),cachedPendingCommandCRCs[frameCount][index]);

								string sErr = "Player: " + getHumanPlayerName() +
											  " got a Network CRC error, CRC's do not match, server CRC = " +
											  uIntToStr(cachedPendingCommandCRCs[frameCount][index]) + ", local CRC = " +
											  uIntToStr(getNetworkPlayerFactionCRC(index));
								sendTextMessage(sErr,-1, true,"");
								DisplayErrorMessage(sErr);
								sleep(1);

								setQuit(true);
								close();
							}
						}
					}
					cachedPendingCommandCRCs.erase(frameCount);
				}
				if(waitForData == true) {
					timeClientWaitedForLastMessage = chrono.getMillis();
					chrono.stop();
				}
				safeMutex.ReleaseLock(true);

				result = true;
				break;
			}
			else {
				safeMutex.ReleaseLock(true);
				// No data for this frame
				if(waitForData == false) {
					if(SystemFlags::VERBOSE_MODE_ENABLED) printf("Client waiting for packet for frame: %d, copyCachedLastPendingFrameCount = %lld\n",frameCount,(long long int)copyCachedLastPendingFrameCount);
					chrono.start();
				}
				if(copyCachedLastPendingFrameCount > frameCountAsUInt64) {
					break;
				}

				if(waitForData == false) {
					waitForData = true;
					sleep(0);
				}

				waitCount++;
				//printf("Client waiting for packet for frame: %d, currentCachedPendingCommandsIndex = %d, cachedPendingCommandsIndex = %lld\n",frameCount,currentCachedPendingCommandsIndex,(long long int)cachedPendingCommandsIndex);
			}
		}
	}
	if(waitForData == true) {
		if(SystemFlags::VERBOSE_MODE_ENABLED) printf("Client waiting for packet FINISHED for frame: %d, copyCachedLastPendingFrameCount = %lld waitCount = %llu\n",frameCount,(long long int)copyCachedLastPendingFrameCount,(long long unsigned int)waitCount);
	}

	return result;
}

void ClientInterface::updateKeyframe(int frameCount) {
	currentFrameCount = frameCount;

	//printf("In updateKeyFrame: %d\n",currentFrameCount);

	if(getQuit() == false && getQuitThread() == false) {
		if(networkCommandListThread == NULL) {
			static string mutexOwnerId 	= string(extractFileFromDirectoryPath(__FILE__).c_str()) + string("_") + intToStr(__LINE__);
			networkCommandListThread 	= new ClientInterfaceThread(this);
			networkCommandListThread->setUniqueID(mutexOwnerId);
			networkCommandListThread->start();

			sleep(0);
		}

		getNetworkCommand(frameCount,cachedPendingCommandsIndex);
	}
}

bool ClientInterface::isMasterServerAdminOverride() {
	return (gameSettings.getMasterserver_admin() == this->getSessionKey());
}

void ClientInterface::waitUntilReady(Checksum* checksum) {
	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);

	MutexSafeWrapper safeMutexFlags(flagAccessor,CODE_AT_LINE);
	bool signalServerWhenReadyToStartJoinedGame = this->readyForInGameJoin;
	this->readyForInGameJoin 					= false;
	safeMutexFlags.ReleaseLock();

    Logger &logger= Logger::getInstance();

	Chrono chrono;
	chrono.start();

	// FOR TESTING ONLY - delay to see the client count up while waiting
	//sleep(5000);

	//clientSocket->setBlock(true);
	//send ready message
	NetworkMessageReady networkMessageReady;
	sendMessage(&networkMessageReady);

	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);

	NetworkMessageLoadingStatus networkMessageLoadingStatus(nmls_NONE);

	Lang &lang= Lang::getInstance();

    int64 lastMillisCheck 				= 0;
	uint64 waitLoopIterationCount 		= 0;
	uint64 MAX_LOOP_COUNT_BEFORE_SLEEP 	= 100;
	MAX_LOOP_COUNT_BEFORE_SLEEP 		= Config::getInstance().getInt("NetworkClientLoopGameLoadingCap",intToStr(MAX_LOOP_COUNT_BEFORE_SLEEP).c_str());
	if(MAX_LOOP_COUNT_BEFORE_SLEEP == 0) {
		MAX_LOOP_COUNT_BEFORE_SLEEP = 1;
	}
	int sleepMillis = Config::getInstance().getInt("NetworkClientLoopGameLoadingCapSleepMillis","10");

	//wait until we get a ready message from the server
	while(true)	{
		// FOR TESTING ONLY - delay to see the client count up while waiting
		//sleep(2000);

		waitLoopIterationCount++;
		if(waitLoopIterationCount > 0 &&
			waitLoopIterationCount % MAX_LOOP_COUNT_BEFORE_SLEEP == 0) {
			sleep(sleepMillis);
			waitLoopIterationCount = 0;
		}

		if(isConnected() == false) {
			if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);

			string sErr = "Error, Server has disconnected!";
            DisplayErrorMessage(sErr);

            if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);

            setQuit(true);
            close();

            if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
            return;
		}
		NetworkMessageType networkMessageType = getNextMessageType();

		// consume old messages from the lobby
		bool discarded = shouldDiscardNetworkMessage(networkMessageType);
		if(discarded == false) {
			if(networkMessageType == nmtReady) {
				if(receiveMessage(&networkMessageReady)) {
					if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
					break;
				}
			}
			else if(networkMessageType == nmtLoadingStatusMessage) {
				if(receiveMessage(&networkMessageLoadingStatus)) {
					if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
				}
			}
			else if(networkMessageType == nmtQuit) {
				NetworkMessageQuit networkMessageQuit;
				if(receiveMessage(&networkMessageQuit)) {
					if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);

					DisplayErrorMessage(lang.getString("GameCancelledByUser"));

					if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);

					setQuit(true);
					close();

					if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
					return;

				}
			}
			else if(networkMessageType == nmtCommandList) {
				//make sure we read the message
				NetworkMessageCommandList networkMessageCommandList;
				bool gotCmd = receiveMessage(&networkMessageCommandList);
				if(gotCmd == false) {
					throw megaglest_runtime_error("error retrieving nmtCommandList returned false!");
				}
			}
			else if(networkMessageType == nmtInvalid) {
				if(chrono.getMillis() > readyWaitTimeout) {
					if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);

			    	Lang &lang= Lang::getInstance();
			    	const vector<string> languageList = this->gameSettings.getUniqueNetworkPlayerLanguages();
			    	for(unsigned int i = 0; i < languageList.size(); ++i) {
			    		string sErr = "Timeout waiting for server";
						if(lang.hasString("TimeoutWaitingForServer",languageList[i]) == true) {
							sErr = lang.getString("TimeoutWaitingForServer",languageList[i]);
						}
						bool echoLocal = lang.isLanguageLocal(lang.getLanguage());
						sendTextMessage(sErr,-1,echoLocal,languageList[i]);

						if(echoLocal) {
							DisplayErrorMessage(sErr);
						}
			    	}

					if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);

					sleep(1);
					setQuit(true);
					close();

					if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
					return;
				}
				else {
					if(chrono.getMillis() % 100 == 0) {
						lastMillisCheck = (chrono.getMillis() / 1000);

						char szBuf[8096]="";
						string updateTextFormat = "Waiting for network: %lld seconds elapsed (maximum wait time: %d seconds)";
						if(lang.hasString("NetworkGameClientLoadStatus") == true) {
							updateTextFormat =  lang.getString("NetworkGameClientLoadStatus");
						}

						string waitForHosts = "";
						if((networkMessageLoadingStatus.getStatus() & nmls_PLAYER1_CONNECTED) == nmls_PLAYER1_CONNECTED) {
							if((networkMessageLoadingStatus.getStatus() & nmls_PLAYER1_READY) != nmls_PLAYER1_READY) {
								if(waitForHosts != "") {
									waitForHosts += ", ";
								}
								waitForHosts += gameSettings.getNetworkPlayerNameByPlayerIndex(0);
							}
						}
						if((networkMessageLoadingStatus.getStatus() & nmls_PLAYER2_CONNECTED) == nmls_PLAYER2_CONNECTED) {
							if((networkMessageLoadingStatus.getStatus() & nmls_PLAYER2_READY) != nmls_PLAYER2_READY) {
								if(waitForHosts != "") {
									waitForHosts += ", ";
								}
								waitForHosts += gameSettings.getNetworkPlayerNameByPlayerIndex(1);
							}
						}
						if((networkMessageLoadingStatus.getStatus() & nmls_PLAYER3_CONNECTED) == nmls_PLAYER3_CONNECTED) {
							if((networkMessageLoadingStatus.getStatus() & nmls_PLAYER3_READY) != nmls_PLAYER3_READY) {
								if(waitForHosts != "") {
									waitForHosts += ", ";
								}
								waitForHosts += gameSettings.getNetworkPlayerNameByPlayerIndex(2);
							}
						}
						if((networkMessageLoadingStatus.getStatus() & nmls_PLAYER4_CONNECTED) == nmls_PLAYER4_CONNECTED) {
							if((networkMessageLoadingStatus.getStatus() & nmls_PLAYER4_READY) != nmls_PLAYER4_READY) {
								if(waitForHosts != "") {
									waitForHosts += ", ";
								}
								waitForHosts += gameSettings.getNetworkPlayerNameByPlayerIndex(3);
							}
						}
						if((networkMessageLoadingStatus.getStatus() & nmls_PLAYER5_CONNECTED) == nmls_PLAYER5_CONNECTED) {
							if((networkMessageLoadingStatus.getStatus() & nmls_PLAYER5_READY) != nmls_PLAYER5_READY) {
								if(waitForHosts != "") {
									waitForHosts += ", ";
								}
								waitForHosts += gameSettings.getNetworkPlayerNameByPlayerIndex(4);
							}
						}
						if((networkMessageLoadingStatus.getStatus() & nmls_PLAYER6_CONNECTED) == nmls_PLAYER6_CONNECTED) {
							if((networkMessageLoadingStatus.getStatus() & nmls_PLAYER6_READY) != nmls_PLAYER6_READY) {
								if(waitForHosts != "") {
									waitForHosts += ", ";
								}
								waitForHosts += gameSettings.getNetworkPlayerNameByPlayerIndex(5);
							}
						}
						if((networkMessageLoadingStatus.getStatus() & nmls_PLAYER7_CONNECTED) == nmls_PLAYER7_CONNECTED) {
							if((networkMessageLoadingStatus.getStatus() & nmls_PLAYER7_READY) != nmls_PLAYER7_READY) {
								if(waitForHosts != "") {
									waitForHosts += ", ";
								}
								waitForHosts += gameSettings.getNetworkPlayerNameByPlayerIndex(6);
							}
						}
						if((networkMessageLoadingStatus.getStatus() & nmls_PLAYER8_CONNECTED) == nmls_PLAYER8_CONNECTED) {
							if((networkMessageLoadingStatus.getStatus() & nmls_PLAYER8_READY) != nmls_PLAYER8_READY) {
								if(waitForHosts != "") {
									waitForHosts += ", ";
								}
								waitForHosts += gameSettings.getNetworkPlayerNameByPlayerIndex(7);
							}
						}

						if(waitForHosts == "") {
							waitForHosts = lang.getString("Server");
						}
						snprintf(szBuf,8096,updateTextFormat.c_str(),(long long int)lastMillisCheck,int(readyWaitTimeout / 1000));

						char szBuf1[8096]="";
						string statusTextFormat =  "Waiting for players: %s";
						if(lang.hasString("NetworkGameStatusWaiting") == true) {
							statusTextFormat = lang.getString("NetworkGameStatusWaiting");
						}
						snprintf(szBuf1,8096,statusTextFormat.c_str(),waitForHosts.c_str());

						logger.add(szBuf, true, szBuf1);

						sleep(0);
					}
				}
			}
			else {
				if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
				sendTextMessage("Unexpected network message: " + intToStr(networkMessageType),-1, true,"");

				if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);

				DisplayErrorMessage(string(extractFileFromDirectoryPath(__FILE__).c_str()) + "::" + string(__FUNCTION__) + " Unexpected network message: " + intToStr(networkMessageType));

				if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);

				sleep(1);
				setQuit(true);
				close();

				if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
				return;
			}

			Shared::Platform::Window::handleEvent();
			// sleep a bit
			sleep(waitSleepTime);
		}
	}

	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);

	//check checksum
	if(getJoinGameInProgress() == false &&
		networkMessageReady.getChecksum() != checksum->getSum()) {

		if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);

    	Lang &lang= Lang::getInstance();
    	const vector<string> languageList = this->gameSettings.getUniqueNetworkPlayerLanguages();
    	for(unsigned int langIndex = 0; langIndex < languageList.size(); ++langIndex) {

    		string sErr = "Checksum error, you don't have the same data as the server";
			if(lang.hasString("CheckSumGameLoadError",languageList[langIndex]) == true) {
				sErr = lang.getString("CheckSumGameLoadError",languageList[langIndex]);
			}
			bool echoLocal = lang.isLanguageLocal(lang.getLanguage());
			sendTextMessage(sErr,-1,echoLocal,languageList[langIndex]);

			string playerNameStr = "Player with error is: " + getHumanPlayerName();
			if(lang.hasString("CheckSumGameLoadPlayer",languageList[langIndex]) == true) {
				playerNameStr = lang.getString("CheckSumGameLoadPlayer",languageList[langIndex]) + " " + getHumanPlayerName();
			}
			sendTextMessage(playerNameStr,-1,echoLocal,languageList[langIndex]);

    		string sErr1 = "Client Checksum: " + intToStr(checksum->getSum());
			if(lang.hasString("CheckSumGameLoadClient",languageList[langIndex]) == true) {
				sErr1 = lang.getString("CheckSumGameLoadClient",languageList[langIndex]) + " " + intToStr(checksum->getSum());
			}

			sendTextMessage(sErr1,-1,echoLocal,languageList[langIndex]);

    		string sErr2 = "Server Checksum: " + intToStr(networkMessageReady.getChecksum());
			if(lang.hasString("CheckSumGameLoadServer",languageList[langIndex]) == true) {
				sErr2 = lang.getString("CheckSumGameLoadServer",languageList[langIndex]) + " " + intToStr(networkMessageReady.getChecksum());
			}
			sendTextMessage(sErr2,-1,echoLocal,languageList[langIndex]);

			if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d %s %s %s\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,sErr.c_str(),sErr1.c_str(),sErr2.c_str());

			if(echoLocal == true) {
				if(Config::getInstance().getBool("NetworkConsistencyChecks")) {
					// error message and disconnect only if checked
					if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);

					string niceError = sErr + string("\n") + sErr1 + string("\n") + sErr2;
					DisplayErrorMessage(niceError);
				}
			}
    	}

		if(Config::getInstance().getBool("NetworkConsistencyChecks")) {
			// error message and disconnect only if checked
			if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);

			sleep(1);
			setQuit(true);

			if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);

			close();
       	}
        return;
	}

	MutexSafeWrapper safeMutexFlags2(flagAccessor,CODE_AT_LINE);
	this->joinGameInProgress 		= false;
	this->joinGameInProgressLaunch 	= false;

	//printf("Client signalServerWhenReadyToStartJoinedGame = %d\n",signalServerWhenReadyToStartJoinedGame);
	if(signalServerWhenReadyToStartJoinedGame == true) {

    	Lang &lang= Lang::getInstance();
    	const vector<string> languageList = this->gameSettings.getUniqueNetworkPlayerLanguages();
    	for(unsigned int langIndex = 0; langIndex < languageList.size(); ++langIndex) {

			string sText = "Player: %s is joining the game now.";
			if(lang.hasString("JoinPlayerToCurrentGameLaunchDone",languageList[langIndex]) == true) {
				sText = lang.getString("JoinPlayerToCurrentGameLaunchDone",languageList[langIndex]);
			}

			if(clientSocket != NULL && clientSocket->isConnected() == true) {
				string playerNameStr = getHumanPlayerName();
				char szBuf[8096]="";
				snprintf(szBuf,8096,sText.c_str(),playerNameStr.c_str());

				sendTextMessage(szBuf,-1,false,languageList[langIndex]);
			}
    	}

		this->resumeInGameJoin = true;
		safeMutexFlags2.ReleaseLock();
	}
	else {
		safeMutexFlags2.ReleaseLock();
		// delay the start a bit, so clients have more room to get messages
		// This is to ensure clients don't start ahead of the server and thus
		// constantly freeze because they are waiting for the server to catch up
		sleep(120);
	}

	// This triggers LAG update packets to begin as required
	lastNetworkCommandListSendTime = time(NULL);

	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] END\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__);
}

void ClientInterface::sendResumeGameMessage() {
	NetworkMessageReady networkMessageReady;
	sendMessage(&networkMessageReady);
}

void ClientInterface::sendTextMessage(const string &text, int teamIndex, bool echoLocal,
		string targetLanguage) {

	string humanPlayerName = getHumanPlayerName();
	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] humanPlayerName = [%s] playerIndex = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,humanPlayerName.c_str(),playerIndex);

	NetworkMessageText networkMessageText(text, teamIndex,playerIndex,targetLanguage);
	sendMessage(&networkMessageText);

	if(echoLocal == true) {
		ChatMsgInfo msg(networkMessageText.getText().c_str(),networkMessageText.getTeamIndex(),networkMessageText.getPlayerIndex(),targetLanguage);
		this->addChatInfo(msg);
	}
}

void ClientInterface::sendMarkCellMessage(Vec2i targetPos, int factionIndex, string note,int playerIndex) {
	string humanPlayerName = getHumanPlayerName();
	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] humanPlayerName = [%s] playerIndex = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,humanPlayerName.c_str(),playerIndex);

	NetworkMessageMarkCell networkMessageMarkCell(targetPos,factionIndex, note,playerIndex);
	sendMessage(&networkMessageMarkCell);
}

void ClientInterface::sendHighlightCellMessage(Vec2i targetPos, int factionIndex) {
	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] playerIndex = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,playerIndex);

	NetworkMessageHighlightCell networkMessageHighlightCell(targetPos,factionIndex);
	sendMessage(&networkMessageHighlightCell);
}

void ClientInterface::sendUnMarkCellMessage(Vec2i targetPos, int factionIndex) {
	string humanPlayerName = getHumanPlayerName();
	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] humanPlayerName = [%s] playerIndex = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,humanPlayerName.c_str(),playerIndex);

	NetworkMessageUnMarkCell networkMessageMarkCell(targetPos,factionIndex);
	sendMessage(&networkMessageMarkCell);
}

void ClientInterface::sendPingMessage(int32 pingFrequency, int64 pingTime) {
	NetworkMessagePing networkMessagePing(pingFrequency,pingTime);
	sendMessage(&networkMessagePing);
}

string ClientInterface::getNetworkStatus() {
	std::string label = Lang::getInstance().getString("Server") + ": " + serverName;
	//float pingTime = getThreadedPingMS(getServerIpAddress().c_str());
	char szBuf[8096]="";
	snprintf(szBuf,8096,"%s",label.c_str());

	return szBuf;
}

NetworkMessageType ClientInterface::waitForMessage(int waitMicroseconds)
{
	// Debug!
/*
    sendTextMessage("Timeout waiting for message",-1);
    DisplayErrorMessage("Timeout waiting for message");
    quit= true;
    close();
    return;
*/

	uint64 loopCount = 0;
	Chrono chronoPerf;
	if(debugClientInterfacePerf == true) {
		chronoPerf.start();
	}

	Chrono chrono;
	chrono.start();

	NetworkMessageType msg = nmtInvalid;
	while(	msg == nmtInvalid &&
			getQuitThread() == false) {

		msg = getNextMessageType(waitMicroseconds);
		if(msg == nmtInvalid) {
			if(chrono.getMillis() % 250 == 0 && isConnected() == false) {
				if(getQuit() == false) {
					//throw megaglest_runtime_error("Disconnected");
					//sendTextMessage("Server has Disconnected.",-1);
					DisplayErrorMessage("Server has Disconnected.");
					setQuit(true);
				}
				close();
				return msg;
			}

			if(chrono.getMillis() > messageWaitTimeout) {
				if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);

				Lang &lang= Lang::getInstance();
		    	const vector<string> languageList = this->gameSettings.getUniqueNetworkPlayerLanguages();
		    	for(unsigned int langIndex = 0; langIndex < languageList.size(); ++langIndex) {

		    		string msg = "Timeout waiting for message.";
		    		if(lang.hasString("TimeoutWaitingForMessage",languageList[langIndex]) == true) {
		    			msg = lang.getString("TimeoutWaitingForMessage",languageList[langIndex]);
		    		}

					sendTextMessage(msg,-1, lang.isLanguageLocal(languageList[langIndex]),languageList[langIndex]);
					if(lang.isLanguageLocal(languageList[langIndex]) == true) {
						DisplayErrorMessage(msg);
					}
		    	}

		    	sleep(1);
		    	setQuit(true);
				close();
				return msg;
			}
			// Sleep every x milli-seconds we wait to let other threads work
			else if(chrono.getMillis() % 20 == 0) {
				sleep(5);
			}
		}

		if(debugClientInterfacePerf == true) {
			loopCount++;
			if(chronoPerf.getMillis() >= 100) {
				printf("Client waitForMessage loopCount = %llu\n",(long long unsigned int)loopCount);

				loopCount = 0;
				chronoPerf.start();
			}
		}
	}

	if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 1) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] waiting took %lld msecs, msg = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,chrono.getMillis(),msg);

	return msg;
}

void ClientInterface::quitGame(bool userManuallyQuit)
{
	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] userManuallyQuit = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,userManuallyQuit);

    if(clientSocket != NULL && userManuallyQuit == true) {
    	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);

		Lang &lang= Lang::getInstance();
    	const vector<string> languageList = this->gameSettings.getUniqueNetworkPlayerLanguages();
    	for(unsigned int langIndex = 0; langIndex < languageList.size(); ++langIndex) {

    		string msg = "has chosen to leave the game!";
    		if(lang.hasString("PlayerLeftGame",languageList[langIndex]) == true) {
    			msg = lang.getString("PlayerLeftGame",languageList[langIndex]);
    		}

			sendTextMessage(msg,-1, lang.isLanguageLocal(languageList[langIndex]),languageList[langIndex]);
    	}
    	sleep(1);
        close();
    }

    if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Lined: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
}

void ClientInterface::close(bool lockMutex) {
	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] START, clientSocket = %p\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,clientSocket);

	MutexSafeWrapper safeMutex(NULL,CODE_AT_LINE);
	if(lockMutex == true) {
		safeMutex.setMutex(networkCommandListThreadAccessor,CODE_AT_LINE);
	}
	shutdownNetworkCommandListThread(safeMutex);

	delete clientSocket;
	clientSocket = NULL;

	safeMutex.ReleaseLock();

	connectedTime = 0;
	gotIntro = false;

	MutexSafeWrapper safeMutexFlags(flagAccessor,CODE_AT_LINE);
	this->joinGameInProgress 		= false;
	this->joinGameInProgressLaunch 	= false;
	this->readyForInGameJoin 		= false;

	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] END\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
}

void ClientInterface::close() {
	close(true);
}

void ClientInterface::discoverServers(DiscoveredServersInterface *cb) {
	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);

	ClientSocket::discoverServers(cb);

	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
}
void ClientInterface::stopServerDiscovery() {
	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);

	ClientSocket::stopBroadCastClientThread();

	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
}

void ClientInterface::sendSwitchSetupRequest(string selectedFactionName, int8 currentSlotIndex,
											int8 toSlotIndex,int8 toTeam, string networkPlayerName,
											int8 networkPlayerStatus, int8 flags,
											string language) {
	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] networkPlayerName [%s] flags = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,networkPlayerName.c_str(),flags);
	SwitchSetupRequest message = SwitchSetupRequest(selectedFactionName,
							currentSlotIndex, toSlotIndex,toTeam,networkPlayerName,
							networkPlayerStatus, flags,language);
	sendMessage(&message);
	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
}

bool ClientInterface::shouldDiscardNetworkMessage(NetworkMessageType networkMessageType) {
	bool discard = false;

	switch(networkMessageType) {
		case nmtIntro:
			{
			discard = true;
			NetworkMessageIntro msg = NetworkMessageIntro();
			this->receiveMessage(&msg);
			}
			break;
		case nmtPing:
			{
			discard = true;
			NetworkMessagePing msg = NetworkMessagePing();
			this->receiveMessage(&msg);
			this->setLastPingInfo(msg);
			}
			break;
		case nmtLaunch:
			{
			discard = true;
			NetworkMessageLaunch msg = NetworkMessageLaunch();
			this->receiveMessage(&msg);
			}
			break;
		case nmtText:
			{
			if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] got nmtText\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
			discard = true;
			NetworkMessageText netMsg = NetworkMessageText();
			this->receiveMessage(&netMsg);

    		ChatMsgInfo msg(netMsg.getText().c_str(),netMsg.getTeamIndex(),netMsg.getPlayerIndex(),netMsg.getTargetLanguage());
    		this->addChatInfo(msg);
			}
			break;

        case nmtMarkCell:
			{
			discard = true;
			NetworkMessageMarkCell networkMessageMarkCell;
			receiveMessage(&networkMessageMarkCell);

			MarkedCell msg(networkMessageMarkCell.getTarget(),
						   networkMessageMarkCell.getFactionIndex(),
						   networkMessageMarkCell.getText().c_str(),
						   networkMessageMarkCell.getPlayerIndex());
			this->addMarkedCell(msg);
			}
			break;

        case nmtUnMarkCell:
			{
			discard = true;
			NetworkMessageUnMarkCell networkMessageMarkCell;
			receiveMessage(&networkMessageMarkCell);

			UnMarkedCell msg(networkMessageMarkCell.getTarget(),
						   networkMessageMarkCell.getFactionIndex());
			this->addUnMarkedCell(msg);
			}
			break;

        case nmtHighlightCell:
			{
			discard = true;
			NetworkMessageHighlightCell networkMessageHighlightCell;
			receiveMessage(&networkMessageHighlightCell);

			MarkedCell msg(networkMessageHighlightCell.getTarget(),
					networkMessageHighlightCell.getFactionIndex(),
						   "none",-1);
			this->setHighlightedCell(msg);
			}
			break;

		case nmtSynchNetworkGameData:
			{
			discard = true;
			NetworkMessageSynchNetworkGameData msg = NetworkMessageSynchNetworkGameData();
			this->receiveMessage(&msg);
			}
			break;
		case nmtSynchNetworkGameDataStatus:
			{
			discard = true;
			NetworkMessageSynchNetworkGameDataStatus msg = NetworkMessageSynchNetworkGameDataStatus();
			this->receiveMessage(&msg);
			}
			break;
		case nmtSynchNetworkGameDataFileCRCCheck:
			{
			discard = true;
			NetworkMessageSynchNetworkGameDataFileCRCCheck msg = NetworkMessageSynchNetworkGameDataFileCRCCheck();
			this->receiveMessage(&msg);
			}
			break;
		case nmtSynchNetworkGameDataFileGet:
			{
			discard = true;
			NetworkMessageSynchNetworkGameDataFileGet msg = NetworkMessageSynchNetworkGameDataFileGet();
			this->receiveMessage(&msg);
			}
			break;
		case nmtSwitchSetupRequest:
			{
			discard = true;
			SwitchSetupRequest msg = SwitchSetupRequest();
			this->receiveMessage(&msg);
			}
			break;
		case nmtBroadCastSetup:
			{
			discard = true;
			NetworkMessageLaunch msg = NetworkMessageLaunch();
			this->receiveMessage(&msg);
			}
			break;

		case nmtPlayerIndexMessage:
			{
			discard = true;
			PlayerIndexMessage msg = PlayerIndexMessage(0);
			this->receiveMessage(&msg);
			}
			break;
	}

	return discard;
}

string ClientInterface::getHumanPlayerName(int index) {
	string  result = Config::getInstance().getString("NetPlayerName",Socket::getHostName().c_str());

	if(index >= 0 || gameSettings.getThisFactionIndex() >= 0) {
		if(index < 0) {
			index = gameSettings.getThisFactionIndex();
		}
		if(gameSettings.getNetworkPlayerName(index) != "") {
			result = gameSettings.getNetworkPlayerName(index);
		}
	}

	return result;
}

void ClientInterface::setGameSettings(GameSettings *serverGameSettings) {
	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] START\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__);

	gameSettings = *serverGameSettings;

	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] END\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__);
}

void ClientInterface::broadcastGameSetup(const GameSettings *gameSettings) {
	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);

	NetworkMessageLaunch networkMessageLaunch(gameSettings, nmtBroadCastSetup);
	sendMessage(&networkMessageLaunch);

	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
}

void ClientInterface::broadcastGameStart(const GameSettings *gameSettings) {
	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);

	MutexSafeWrapper safeMutexFlags(flagAccessor,CODE_AT_LINE);
	if(this->joinGameInProgress == true) {
		this->joinGameInProgressLaunch = true;
	}
	safeMutexFlags.ReleaseLock();

	//printf("Sending game launch joinGameInProgress: %d\n",joinGameInProgress);

	NetworkMessageLaunch networkMessageLaunch(gameSettings, nmtLaunch);
	sendMessage(&networkMessageLaunch);

	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
}

void ClientInterface::setGameSettingsReceived(bool value) {
	//printf("In [%s:%s] Line: %d gameSettingsReceived = %d value = %d, gameSettingsReceivedCount = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,gameSettingsReceived,value,gameSettingsReceivedCount);
	gameSettingsReceived = value;
	gameSettingsReceivedCount++;
}

}}//end namespace
